# -*- coding: utf-8 -*-

import pickle
import forward_client

g_rpc_func = {}     # { func_name:[func1, func2, ...],  }


def rpc_call(func, eid_dst_list, *args, **kwargs):
    """
    客户端之间的RPC
    支持函数和类的静态函数, 不支持bound_method(bound_method用rpc_bind)
    :param func:  字符串或函数，参数形式为 (src_eid, *args, **kwargs)
    :param eid_dst_list: eid(单播)或eid_list(多播), -1代表其他所有客户端，0代表服务器
    :param args: func的参数
    :param kwargs: func的参数
    :return:
    """
    assert(isinstance(func, str) or not hasattr(func, '__self__'))
    assert(isinstance(eid_dst_list, (int, list, tuple)))
    payload = pickle.dumps((func, args, kwargs), forward_client.ForwardClient.PICKLE_VERSION)

    if eid_dst_list == -1:
        eid_send = [forward_client.ForwardClient.BROADCAST_EID]
    elif isinstance(eid_dst_list, int):
        eid_send = [eid_dst_list]
    else:
        eid_send = eid_dst_list
    forward_client.Get().send_msg(forward_client.ForwardClient.CMD_FORWARD, forward_client.Get().get_self_eid(), eid_send, payload)


def rpc_bind(func_name, func):
    global g_rpc_func
    if func_name not in g_rpc_func:
        g_rpc_func[func_name] = [func]
    else:
        g_rpc_func[func_name].append(func)


def rpc_unbind(func_name, func=None):
    global g_rpc_func
    if func_name not in g_rpc_func:
        return
    if func is None:
        del(g_rpc_func[func_name])
    else:
        try:
            g_rpc_func[func_name].remove(func)
            if not g_rpc_func[func_name]:
                del (g_rpc_func[func_name])
        except ValueError:
            pass


def rpc_init():
    forward_client.Get().bind_cmd_recv(forward_client.ForwardClient.CMD_FORWARD, _rpc_recv_msg)


def rpc_fini():
    global g_rpc_func
    g_rpc_func = {}


def _rpc_recv_msg(src_eid, dst_eid_list, payload):
    global g_rpc_func
    func, args, kwargs = pickle.loads(payload)
    if isinstance(func, str):
        if func in g_rpc_func:
            for each_func in g_rpc_func[func]:
                each_func(src_eid, *args, **kwargs)
        else:
            print("Error! Unknown rpc message, src={}, func_name={}".format(src_eid, func))
            print(g_rpc_func)
    elif callable(func):
        func(src_eid, *args, **kwargs)
    else:
        print("Error! UnCallable rpc message, src={}, func={}".format(src_eid, func))

